#include "RobotBase.h"

#include <OgreException.h>
#include <OgreConfigFile.h>

//-------------------------------------------------------------------------------------
RobotBase::RobotBase(void):
	mRoot(0),
	mPluginsCfg(Ogre::StringUtil::BLANK),
	mResourcesCfg(Ogre::StringUtil::BLANK),
	mShutDown(false),
	mRotate(0)
{
}
//-------------------------------------------------------------------------------------
RobotBase::~RobotBase(void)
{
	delete mRoot;
}
//-------------------------------------------------------------------------------------
bool RobotBase::go(void)
{
#ifdef _DEBUG
	mPluginsCfg = "plugins_d.cfg";
	mResourcesCfg = "resources_d.cfg"
#else
	mPluginsCfg = "plugins.cfg";
	mResourcesCfg = "resources.cfg";
#endif

	if(!setup()) return false;
	createScene();
	Ogre::LogManager::getSingletonPtr()->logMessage("*** Done Creating Scene ***");
	//startOIS();
	createFrameListener();
   	mRoot->addFrameListener(this);
   	Ogre::LogManager::getSingletonPtr()->logMessage("*** Starting to Render ***");
   	mRoot->startRendering();
}
//-------------------------------------------------------------------------------------
//Adjust mouse clipping area
void RobotBase::windowResized(Ogre::RenderWindow* rw)
{
    unsigned int width, height, depth;
    int left, top;
    rw->getMetrics(width, height, depth, left, top);

    const OIS::MouseState &ms = mMouse->getMouseState();
    ms.width = width;
    ms.height = height;
}
//-------------------------------------------------------------------------------------
//Unattach OIS before window shutdown (very important under Linux)
void RobotBase::windowClosed(Ogre::RenderWindow* rw)
{
    //Only close for window that created OIS (the main window in these demos)
    if( rw == mWindow )
    {
        if( mInputManager )
        {
            mInputManager->destroyInputObject( mMouse );
            mInputManager->destroyInputObject( mKeyboard );

            OIS::InputManager::destroyInputSystem(mInputManager);
            mInputManager = 0;
        }
    }
}
//-------------------------------------------------------------------------------------
bool RobotBase::setup(void){
	mRoot = new Ogre::Root(mPluginsCfg);

	Ogre::ConfigFile cf;
	cf.load(mResourcesCfg);

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
	    secName = seci.peekNextKey();
	    Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
	    Ogre::ConfigFile::SettingsMultiMap::iterator i;
	    for (i = settings->begin(); i != settings->end(); ++i)
	    {
	        typeName = i->first;
	        archName = i->second;
	        Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
	            archName, typeName, secName);
	    }
	}

	if(!(mRoot->restoreConfig() || mRoot->showConfigDialog())){
		return false;
	}

	mWindow = mRoot->initialise(true,"Main RenderWindow");

	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	mSceneMgr = mRoot->createSceneManager("DefaultSceneManager");

	Ogre::LogManager::getSingletonPtr()->logMessage("*** Done With Setup ***");

	return true;
}
//-------------------------------------------------------------------------------------
void RobotBase::createCamera(void){

	mCamera = mSceneMgr->createCamera("PlayerCam");

	mCamera->setPosition(Ogre::Vector3(0,0,0));
	mCamera->lookAt(Ogre::Vector3(0,0,0));

	mCamNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode");
	mCamNode->attachObject(mCamera);

	mCamera->setNearClipDistance(.1);
	mCamera->setFarClipDistance(50000);

	if(mRoot->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_INFINITE_FAR_PLANE)){
		mCamera->setFarClipDistance(0);
	}



}
//-------------------------------------------------------------------------------------
void RobotBase::createViewport(void){

	Ogre::Viewport* vp = mWindow->addViewport(mCamera);
	vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
	mCamera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
}
//-------------------------------------------------------------------------------------
void RobotBase::startOIS(void){

	Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;

	mWindow->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

	mInputManager = OIS::InputManager::createInputSystem( pl );

	mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, false ));
	mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, false ));

	Ogre::LogManager::getSingletonPtr()->logMessage("*** Done Initializing OIS ***");
}
//-------------------------------------------------------------------------------------
bool RobotBase::frameRenderingQueued(const Ogre::FrameEvent& evt){


	if(mWindow->isClosed()) return false;
	if(mShutDown) return false;
	mKeyboard->capture();
	mMouse->capture();
	mTrayMgr->frameRenderingQueued(evt);
	speed += mDirection;
	mCamNode->translate(speed * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);
	Ogre::Vector3 drag = 0.0255 * speed;
	speed -= drag;

	return true;
}
//-------------------------------------------------------------------------------------
void RobotBase::destroyScene(void){

	OGRE_DELETE mTerrainGroup;
	OGRE_DELETE mTerrainGlobals;
}
//-------------------------------------------------------------------------------------
void RobotBase::getTerrainImage(bool flipX,bool flipY,Ogre::Image& img){

	img.load("terrain copy8.png",Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	if(flipX)
		img.flipAroundY();
	if(flipY)
		img.flipAroundX();
}
//-------------------------------------------------------------------------------------
void RobotBase::defineTerrain(long x, long y){

	Ogre::String filename = mTerrainGroup->generateFilename(x,y);
	if(Ogre::ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(),filename)){
		mTerrainGroup->defineTerrain(x,y);
	}
	else{
		Ogre::Image img;
		getTerrainImage(x % 2 != 0, y % 2 != 0, img);
		mTerrainGroup->defineTerrain(x,y,&img);
		mTerrainsImported = true;
	}
}
//-------------------------------------------------------------------------------------
void RobotBase::configureTerrainDefaults(Ogre::Light* light){

	mTerrainGlobals->setMaxPixelError(10);
	mTerrainGlobals->setCompositeMapDistance(3000);

	mTerrainGlobals->setLightMapDirection(light->getDerivedDirection());
	mTerrainGlobals->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
	mTerrainGlobals->setCompositeMapDiffuse(light->getDiffuseColour());

	mTerrainGlobals->setCastsDynamicShadows(false);


	Ogre::Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
	defaultimp.terrainSize = 2049;
	defaultimp.worldSize = 12000.0f;
	defaultimp.inputScale = 1000;
	defaultimp.minBatchSize = 33;
	defaultimp.maxBatchSize = 65;


	// textures
	//originally 100,30,200
	    defaultimp.layerList.resize(3);
	    defaultimp.layerList[0].worldSize = 300;
	    defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_diffusespecular.dds");
	    defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_normalheight.dds");
	    defaultimp.layerList[1].worldSize = 100;
	    defaultimp.layerList[1].textureNames.push_back("grass_green-01_diffusespecular.dds");
	    defaultimp.layerList[1].textureNames.push_back("grass_green-01_normalheight.dds");
	    defaultimp.layerList[2].worldSize = 600;
	    defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds");
	    defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds");
}
//-------------------------------------------------------------------------------------
void RobotBase::initBlendMaps(Ogre::Terrain* terrain){

    Ogre::TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1);
    Ogre::TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2);
    Ogre::Real minHeight0 = 70;
    Ogre::Real fadeDist0 = 40;
    Ogre::Real minHeight1 = 70;
    Ogre::Real fadeDist1 = 15;
    float* pBlend0 = blendMap0->getBlendPointer();
    float* pBlend1 = blendMap1->getBlendPointer();
    for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y)
    {
        for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x)
        {
            Ogre::Real tx, ty;

            blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty);
            Ogre::Real height = terrain->getHeightAtTerrainPosition(tx, ty);
            Ogre::Real val = (height - minHeight0) / fadeDist0;
            val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
            *pBlend0++ = val;

            val = (height - minHeight1) / fadeDist1;
            val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
            *pBlend1++ = val;
        }
    }
    blendMap0->dirty();
    blendMap1->dirty();
    blendMap0->update();
    blendMap1->update();
}
//-------------------------------------------------------------------------------------
bool RobotBase::keyPressed( const OIS::KeyEvent& evt ){

	switch(evt.key){

	case OIS::KC_ESCAPE:
		mShutDown = true;
		break;


	case OIS::KC_UP:
		numPhysSteps++;
		break;
	case OIS::KC_W:
	    mDirection.z = -mMove;
	    break;

	case OIS::KC_DOWN:
		if(numPhysSteps > 1)
			numPhysSteps--;
		break;
	case OIS::KC_S:
	    mDirection.z = mMove;
	    break;

	case OIS::KC_LEFT:
	case OIS::KC_A:
	    mDirection.x = -mMove;
	    break;

	case OIS::KC_RIGHT:
	case OIS::KC_D:
	    mDirection.x = mMove;
	    break;

	case OIS::KC_PGDOWN:
	case OIS::KC_E:
	    mDirection.y = -mMove;
	    break;

	case OIS::KC_PGUP:
	case OIS::KC_Q:
	    mDirection.y = mMove;
	    break;

	default:
		break;
	}
	return true;
}
//-------------------------------------------------------------------------------------
bool RobotBase::keyReleased( const OIS::KeyEvent& evt ){

	switch (evt.key)
	{
	case OIS::KC_UP:
		break;
	case OIS::KC_W:
	    mDirection.z = 0;
	    break;

	case OIS::KC_DOWN:
		break;
	case OIS::KC_S:
	    mDirection.z = 0;
	    break;

	case OIS::KC_LEFT:
	case OIS::KC_A:
	    mDirection.x = 0;
	    break;

	case OIS::KC_RIGHT:
	case OIS::KC_D:
	    mDirection.x = 0;
	    break;

	case OIS::KC_PGDOWN:
	case OIS::KC_E:
	    mDirection.y = 0;
	    break;

	case OIS::KC_PGUP:
	case OIS::KC_Q:
	    mDirection.y = 0;
	    break;

	default:
	    break;
	}

	return true;
}
//-------------------------------------------------------------------------------------
bool RobotBase::mouseMoved( const OIS::MouseEvent& evt ){


	mCamNode->yaw(Ogre::Degree(-mRotate * evt.state.X.rel), Ogre::Node::TS_WORLD);
	mCamNode->pitch(Ogre::Degree(-mRotate * evt.state.Y.rel), Ogre::Node::TS_LOCAL);


	powerLevel += evt.state.Z.rel;


	return true;
}
//-------------------------------------------------------------------------------------
bool RobotBase::mousePressed( const OIS::MouseEvent& evt, OIS::MouseButtonID id ){

	//Ogre::Light *light = mSceneMgr->getLight("Light1");
	switch (id)
	{
	case OIS::MB_Left:
	    //ight->setVisible(! light->isVisible());
	    break;
	default:
	    break;
	}
	return true;
}
//-------------------------------------------------------------------------------------
bool RobotBase::mouseReleased( const OIS::MouseEvent& evt, OIS::MouseButtonID id ){return true;}
//-------------------------------------------------------------------------------------
void RobotBase::createFrameListener(void)
{
    Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
    OIS::ParamList pl;
    size_t windowHnd = 0;
    std::ostringstream windowHndStr;


    mWindow->getCustomAttribute("WINDOW", &windowHnd);
    windowHndStr << windowHnd;
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

    mInputManager = OIS::InputManager::createInputSystem( pl );

    mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
    mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));

    mMouse->setEventCallback(this);
    mKeyboard->setEventCallback(this);

    //Set initial mouse clipping size
    windowResized(mWindow);

    //Register as a Window listener
    Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

    mTrayMgr = new OgreBites::SdkTrayManager("InterfaceName", mWindow, mMouse, this);
    mTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
    mTrayMgr->hideCursor();
    mInfoLabel = mTrayMgr->createLabel(OgreBites::TL_TOP, "TInfo", "", 700);
    // create a params panel for displaying sample details
    Ogre::StringVector items;
    items.push_back("cam.pX");
    items.push_back("cam.pY");
    items.push_back("cam.pZ");
    items.push_back("");
    items.push_back("cam.oW");
    items.push_back("cam.oX");
    items.push_back("cam.oY");
    items.push_back("cam.oZ");
    items.push_back("");
    items.push_back("Filtering");
    items.push_back("Poly Mode");

    mDetailsPanel = mTrayMgr->createParamsPanel(OgreBites::TL_NONE, "DetailsPanel", 200, items);
    mDetailsPanel->setParamValue(9, "Bilinear");
    mDetailsPanel->setParamValue(10, "Solid");
    mDetailsPanel->hide();
    //mDetailsPanel->show();
    mInfoLabel->show();
    mInfoLabel->setCaption("Loading...");

    mRoot->addFrameListener(this);

	//mCamNode = mCamera->getParentSceneNode();

	mRotate = 0.13;
	mMove = 10;

	mDirection = Ogre::Vector3::ZERO;
	speed = Ogre::Vector3::ZERO;
}
//-------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------
